/**
 * Axios请求封装
 * Versions: 1.1.0
 * Author: void rangers
 * Date: 2021-4-1
 * Desc: 为简化请求对Axios插件做的特别处理
 * From: https://gitee.com/void_rangers/request
 * **/
;
!function (win){
    function Request(param) {
        this.url = param.url; //请求的接口地址，可以是一个处理函数
        this.load = null; //"加载中"效果的返回主体, 可设置 false 禁用
        this.debug = false; //打印请求参数
        this.default = {
            methods: {}, // 额外添加的自定义处理事件
            loading() {}, // 定义"加载中"效果
            hideLoading() {}, // 取消加载中效果
            alert() {}, // 错误提示弹框
            pretreatment(res) { // 请求预处理
                if (res.data.status != 0) {
                    this._alert(res.data.msg || 'ε=(´ο｀*))) 小主~ 网络好像打盹了呢...');
                    return false;
                }
            }
        };
        this.OnlyOnce = false; //私有属性
		this.loadArg = null;	//loading方法的参数
        Object.defineProperty(this, 'headers', {
            value: Object.assign({}, param.headers),
            configurable: true
        });
        this.opts = Object.assign({}, this.default, param);
        this.init();
    }

    Request.prototype = {
        init() {
            let methods = this.opts.methods;
            for (var i in methods) {
                this.__proto__[i] = methods[i];
            }

            Object.defineProperty(this, '_headers', {
                get() {
                    let headers = this.headers;
                    if (this.OnlyOnce) this.OnlyOnce = Number(this.OnlyOnce) - 1;
                    if (!this.OnlyOnce) {
                        Object.defineProperty(this, 'headers', {
                            value: Object.assign({}, this.opts.headers),
                            configurable: true
                        });
                    }
                    return headers;
                },
                set(newHeader) {
                    Object.defineProperty(this, 'headers', {
                        value: Object.assign({}, this.opts.headers, newHeader)
                    });
                }
            });

            console.log('Request Start:', this);
        },
        /**
         * @param {Object} newHeader           新添加的响应头内容
         * @param {Boolean/Number} status      新请求头的可用次数(false: 永久可用, true: 可用一次, {Number}: 可用{Number}次)
         * **/
        setHeader(newHeader, status = false) {
            if (typeof newHeader != 'object') {
                console.error('Response header setting:', 'not an object');
                return false;
            }
            this.OnlyOnce = status;
            this._headers = newHeader;
        },
        /**
         * @param {String/Function} api     接口名称
         * @param {Object} param    请求的参数
         * @param {Function} fn     成功的回调
         * @param {Function} eFn    失败的回调
         * **/
        get(api, param) {
            return this._request('get')(api, param);
        },
        post(api, param, fn, eFn) {
            return this._request('post')(api, param);
        },
        form(api, param, fn, eFn) {
            return this._request('form')(api, param);
        },
        _request(method = 'get') {
            var _this = this;
            return function (api, param, fn, eFn) {
                if (typeof arguments[1] == 'function') {
                    fn = arguments[1];
                    eFn = arguments[2];
                    param = {};
                }
                var AParam = {
                    method: method,
                    url: _this._getUrl(api),
                    headers: _this._headers
                };
                if (!axios) {
                    console.error('Load the AXIOS plug-in first');
                    return false;
                }
                switch (method) {
                    case 'get': // GET 默认使用 application/json
                    case 'GET':
                        AParam['params'] = param;
                        break;
                    case 'form': // 模拟 Form 表单提交
                        AParam['method'] = 'post';
                        AParam['data'] = _this.stringify(param);
                        AParam['headers'] = Object.assign(AParam.headers, {
                            'content-type': 'application/x-www-form-urlencoded'
                        });
                        break;
                    default:
                        AParam['data'] = param;
                }
                if (_this.debug) console.log('Request Axios param:', AParam);
                _this._loading();
                return new Promise((fn, eFn) => {
                    axios(AParam).then(resolve => {
                        if (_this.debug) console.log('Axios resolve:', resolve);
                        _this._hideLoading();
                        if (_this._pretreatment(resolve) != false) {
                            fn && fn(resolve);
                        }
                    }).catch(error => {
                        if (_this.debug) console.error('Axios Error:', error);
                        eFn(error);
                        _this._hideLoading();
                        _this._alert(error || '咦？网络好像跑丢了...');
                    })
                })
            }
        },
        stringify(obj) {
            if (typeof obj != 'object') {
                console.error('not is object!');
                return false;
            }
            var _this = this,
                param = '';
            for (var i in obj) {
                let v = obj[i],
                    str;
                str = _this._format(v, i);
                param += (param ? '&' : '') + str;
            }
            return param;
        },
        loading(param){
			if(param === false){
				this.load = false;
				return false;
			}
			this.loadArg = param;
        },
        _format(data, key) {
            let _this = this,
                param = '', item;
            if (typeof data == 'object' && data !== null) {
                //console.log('_format:', data, key);
                for (var i in data) {
                    if (data.hasOwnProperty(i)) {
                        let val = data[i];
                        if (typeof val == 'object' && val !== null) {
                            item = _this._format(val, key + '[' + i + ']');
                        } else {
                            item = key + '[' + i + ']=' + val;
                        }
                        param += (param ? '&' : '') + item;
                    }
                }
            } else {
                param = key + '=' + data;
            }
            return param;
        },
        _getUrl(api) {
            let url;
            switch (typeof this.url) {
                case 'function':
                    url = this.url(api);
                    break;
                case 'string':
                    url = this.url + api;
                    break;
                default:
                    console.error('Type Error:', 'URL is not of this type!');
                    return false
            }
            return url;
        },
        _loading() {
			//console.log('loadArg:', this.loadArg);
			if(this.load === false) return false;
            this.load = this.opts.loading(this.loadArg);
        },
        _hideLoading() {
            if (this.load) this.opts.hideLoading(this.load);
            this.load = null;
			this.loadArg = '';
        },
        _alert(msg) {
            if (!msg) return false;
            this.opts.alert(msg);
        },
        _pretreatment(res) {
            this.opts.pretreatment.call(this, res);
        }
    };

    win.Request = Request;
}(window);